package Common;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;

/**
 * This is utility class in order to read and write int/double/string to desired position in a byte array
 * Usaage: ByteArray.writeXXX ( byte [] , int pos , XXX value ) ;
 * XXX can be int/short/float/double/string
 */
public class ByteArray {
	
	public static int readInt ( byte [] buffer, int pos ) throws Exception {
		if ( (pos < 0) || (pos + 3 >= buffer.length) ) throw new Exception ( "Cannot read int from that position" );
		int result = 0 ; 
		for ( int i = 0 ; i < 4 ; i++ ) 
			result = (result << 8 )+  (buffer [ pos+i ] < 0 ? 256+buffer[ pos+i ] : buffer[ pos+i ]) ;
		return result ; 
	}
	
	public static void writeInt ( byte [] buffer, int pos , int numToWrite) throws Exception {
		if ( (pos < 0) || (pos + 3 >= buffer.length) ) throw new Exception ( "Cannot write in that position" );
		buffer [ pos ] = (byte)(numToWrite >> 24) ; 
		buffer [ pos + 1 ] = (byte)(numToWrite >> 16)  ; 
		buffer [ pos + 2 ] = (byte)(numToWrite >> 8) ; 
		buffer [ pos + 3 ] = (byte)(numToWrite) ; 
	}

	public static short readShort ( byte [] buffer, int pos ) throws Exception {
		if ( (pos < 0) || (pos + 1 >= buffer.length) ) throw new Exception ( "Cannot read short from that position" );
		int result = 0 ; 
		for ( int i = 0 ; i < 2 ; i++ ) 
			result = (result << 8 )+  (buffer [ pos+i ] < 0 ? 256+buffer[ pos+i ] : buffer[ pos+i ]) ;
		return (short)result ; 
	}
	
	public static void writeShort ( byte [] buffer, int pos , short numToWrite) throws Exception {
		if ( (pos < 0) || (pos + 1 >= buffer.length) ) throw new Exception ( "Cannot write shoart in that position" );
		buffer [ pos ] = (byte)(numToWrite >> 8) ; 
		buffer [ pos + 1 ] = (byte)(numToWrite) ; 
	}
	
	public static char readChar ( byte [] buffer, int pos ) throws Exception {
		if ( (pos < 0) || (pos + 1 >= buffer.length) ) throw new Exception ( "Cannot read char from that position" );
		int result = 0 ; 
		for ( int i = 0 ; i < 2 ; i++ ) 
			result = (result << 8 )+  (buffer [ pos+i ] < 0 ? 256+buffer[ pos+i ] : buffer[ pos+i ]) ;
		return (char)result ; 
	}
	
	public static void writeChar ( byte [] buffer, int pos , char charToWrite) throws Exception {
		if ( (pos < 0) || (pos + 1 >= buffer.length) ) throw new Exception ( "Cannot write char in that position" );
		buffer [ pos ] = (byte)(charToWrite >> 8) ; 
		buffer [ pos + 1 ] = (byte)(charToWrite) ; 
	}
	
	public static float readFloat ( byte [] buffer , int pos ) throws Exception {
		int result = readInt ( buffer, pos ) ;
		return Float.intBitsToFloat ( result ) ;
	}
	
	public static void writeFloat ( byte [] buffer , int pos , float valueToWrite ) throws Exception {
		writeInt ( buffer, pos , Float.floatToIntBits(valueToWrite)) ;
	}
	
	public static Double readDouble ( byte [] buffer , int pos ) throws Exception {
		DataInputStream scanner = getFromPos ( buffer , pos , 8 ) ;
		Double result = scanner.readDouble(); 
		scanner.close() ; 
		return result ; 
	}
	
	public static void writeDouble ( byte [] buffer , int pos , double valueToWrite ) throws Exception {
		ByteArrayOutputStream  tmp = new ByteArrayOutputStream  () ; 
		DataOutputStream  out = new DataOutputStream  (  tmp  ) ;
		out.writeDouble( valueToWrite ) ; 
		byte[] result = tmp.toByteArray() ; 
		System.arraycopy( result , 0, buffer, pos , result.length ) ;
	}
	
	/**
	 * @param len: This is maximal length of the string to read. 
	 */
	public static String readString ( byte [] buffer , int pos ) throws Exception {
		int len = readInt ( buffer, pos ) ; 
		byte tmp [ ] = new byte [ len ] ;
		System.arraycopy(buffer, pos, tmp, 0, len) ;
		return new String ( buffer, pos + 4, len ) ; 
	}
	
	public static void writeString ( byte [] buffer , int pos , String valueToWrite ) throws Exception {
		byte[] result = valueToWrite.getBytes() ;  
		writeInt ( buffer, pos, result.length ) ; 
		System.arraycopy( result , 0, buffer, pos + 4 , result.length ) ;
	}

	private static DataInputStream getFromPos ( byte [] buffer , int pos , int len ) {
		byte tmp [ ] = new byte [ len ] ; 
		System.arraycopy(buffer, pos, tmp, 0, len) ;
		return new DataInputStream ( new ByteArrayInputStream( tmp )) ;		
	}
	
}
